Skip to content

Search: make universal results mode-aware#658

Merged
BigSimmo merged 16 commits into
mainfrom
codex/universal-search-mode-ranking
Jul 14, 2026
Merged

Search: make universal results mode-aware#658
BigSimmo merged 16 commits into
mainfrom
codex/universal-search-mode-ranking

Conversation

@BigSimmo

@BigSimmo BigSimmo commented Jul 14, 2026

Copy link
Copy Markdown
Owner

Summary

  • make the shared search composer search every canonical server domain while preferring the active mode
  • add Specifiers coverage, local/private Favourites matching, stable deduplication, and explicit cross-mode labels
  • add phone listbox results and compact submitted "Also matches" results across mode result pages
  • preserve auth/owner scoping, rate limits, cancellation, per-domain timeouts, lexical previews, partial failures, and private local favourite state

Why

The shared composer was visually universal but did not consistently search or rank all mode-owned content. Queries now remain mode-aware without hiding strong matches from other modes.

Areas touched

Universal search API/contract, mode/domain ownership, command surface, submitted result summaries, Favourites client index, Specifiers/Tools configuration, and focused Vitest/Playwright coverage.

Verification

  • npm run verify:pr-local -- --files <18 universal-search files> — passed on the current merged tip
  • 247 test files passed; 2,307 tests passed; 1 skipped
  • production build passed; 653 pages generated; client bundle secret scan passed
  • offline RAG contract suite passed; 21 files and 281 tests
  • focused universal-search unit suite passed; 46 tests
  • focused universal-search Chromium suite passed; 9 tests
  • full Chromium UI run: 163/166 passed; two timing failures passed in isolation; one existing mobile evidence-drawer stress failure remains because the fixed composer intercepts the click

Checks not run

No live search evaluation, owner-live test, Supabase/OpenAI provider check, hosted release check, or production data operation was run. Production readiness in the isolated worktree remains environment-blocked by absent Supabase/OpenAI variables.

Production/governance

No database migration or production environment change. Favourites remain client-local and are never sent to the universal-search API. Existing owner/public scoping and partial-failure behavior are preserved.

Summary by CodeRabbit

  • New Features
    • Universal search now supports specifiers and is mode-aware, improving result ordering and “view all” navigation.
    • Added an “also matches” section across multiple search pages, showing related results from other modes (with “Current mode” / “Also in …” labels).
    • Saved favourites now appear in universal search suggestions with clear “Saved” badges.
  • Bug Fixes
    • Improved cross-mode suggestion visibility and refined “best match” behavior for favourites mode.
    • Universal search dropdown now opens more reliably on mobile and closes on scroll.
  • Tests
    • Expanded Playwright and API test coverage for specifiers, mode/context ordering, favourites, and mobile interactions.

@supabase

supabase Bot commented Jul 14, 2026

Copy link
Copy Markdown

This pull request has been ignored for the connected project sjrfecxgysukkwxsowpy because there are no changes detected in supabase directory. You can change this behaviour in Project Integrations Settings ↗︎.


Preview Branches by Supabase.
Learn more about Supabase Branching ↗︎.

@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review
📝 Walkthrough

Walkthrough

Universal search now supports mode-aware requests, specifier results, preferred-domain ordering, saved favourites, and cross-mode “also matches” surfaces across search pages and dashboards. Client caching, API validation, dropdown behavior, navigation, and UI tests are updated.

Changes

Universal search foundation

Layer / File(s) Summary
Search domains, mode context, and ordering
src/lib/app-modes.ts, src/lib/universal-search-domains.ts, src/lib/universal-search-mode-context.ts, src/lib/universal-search.ts, src/lib/search-command-surface.ts, tests/*
Adds the specifiers domain, mode-to-domain mappings, mode-aware ordering metadata, specifier result adapters, view-all routing, command-surface configuration, and contract tests.
API and client mode propagation
src/app/api/search/universal/route.ts, src/components/clinical-dashboard/use-universal-search.ts, tests/universal-search.test.ts
Validates and forwards mode, makes cached results mode-specific, and exposes contextMode and preferredDomains in client state.

Command surface and saved favourites

Layer / File(s) Summary
Saved results and cross-mode dropdown behavior
src/components/clinical-dashboard/universal-search-command-surface.tsx, tests/ui-tools.spec.ts
Ranks local favourites, renders saved entries, updates current-mode labels and filtering, reorders answer actions, and opens or dismisses the dropdown based on focus and scrolling rather than viewport gating.

Cross-mode result surfaces

Layer / File(s) Summary
Also-matches component and page integration
src/components/clinical-dashboard/universal-search-also-matches.tsx, src/components/ClinicalDashboard.tsx, src/components/clinical-dashboard/*, src/components/services/*, src/components/forms/*, src/components/specifiers/*
Adds grouped cross-mode matches with deduplicated links and view-all navigation, then mounts the component across dashboard and search-result views.
Cross-mode UI coverage
tests/ui-universal-search.spec.ts, tests/ui-smoke.spec.ts
Tests mode-specific ordering, saved favourites, phone typeahead, submitted cross-mode results, answer-mode smart affordances, and responsive overflow.

Estimated code review effort: 4 (Complex) | ~60 minutes

Sequence Diagram(s)

sequenceDiagram
  participant User
  participant SearchSurface
  participant UniversalSearchAPI
  participant runUniversalSearch
  participant AlsoMatches
  User->>SearchSurface: enter query and select mode
  SearchSurface->>UniversalSearchAPI: request query with mode
  UniversalSearchAPI->>runUniversalSearch: run context-aware search
  runUniversalSearch-->>UniversalSearchAPI: ordered domain groups
  UniversalSearchAPI-->>SearchSurface: mode-specific results
  SearchSurface->>AlsoMatches: render query and current mode
  AlsoMatches-->>User: show matches in other modes
Loading

Possibly related PRs

  • BigSimmo/Database#499: Modifies universal-search client wiring and mode-domain mapping used by this change.
  • BigSimmo/Database#660: Changes the app-mode registry that supplies the mode identifiers used by universal search.
  • BigSimmo/Database#430: Touches the same narrow-viewport universal dropdown and listbox test flows.
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 8.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and clearly reflects the main change: making universal search results mode-aware.
Description check ✅ Passed The description covers the summary, rationale, impacted areas, verification, and skipped checks with sufficient detail.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch codex/universal-search-mode-ranking

Comment @coderabbitai help to get the list of available commands.

@BigSimmo
BigSimmo enabled auto-merge July 14, 2026 11:45

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 01f587db85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/ClinicalDashboard.tsx Outdated
@BigSimmo

Copy link
Copy Markdown
Owner Author

@codex resolve actionable Codex review findings for this pull request and current head using the repository instructions. This is the pull request's single automatic repair pass: do not perform a fresh review, create new standalone findings, or request another review. Work only the existing unresolved Codex threads on the current head. Always fix P0 and P1 findings. For P2 and lower findings, fix only clear, scoped, low-risk issues; otherwise disposition them with a concise reason. After fixing or dispositioning a thread, reply in that thread with as the first line, followed by a concise summary; that marker authorizes the workflow to close that exact thread. If human input or new authorization is required, do not use the marker and leave the thread open with the blocker. Finish only after every actionable thread is fixed or dispositioned and closed, or explicitly left open for a human decision. Do not update the branch from main, address unrelated reviews, broaden scope, or create more than one scoped fix commit. Do not use external APIs, paid services, credentials, dependency changes, or broad refactors unless explicitly authorized. Add targeted tests where behavior changes and run the narrowest relevant validation.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 01f587db85

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

@github-actions

github-actions Bot commented Jul 14, 2026

Copy link
Copy Markdown

CI triage

CI failed on this PR. Automated classification of the 3 failed job(s):

  • Critical UI smokepossible known flake: UI/Playwright job; check tests/flake-ledger.json (tests/ui-smoke.spec.ts, tests/ui-smoke.spec.ts, tests/ui-tools.spec.ts, tests/ui-tools.spec.ts) and re-run before bisecting.
  • UI regressionpossible known flake: UI/Playwright job; check tests/flake-ledger.json (tests/ui-smoke.spec.ts, tests/ui-smoke.spec.ts, tests/ui-tools.spec.ts, tests/ui-tools.spec.ts) and re-run before bisecting.
  • PR requiredpossible known flake: UI/Playwright job; check tests/flake-ledger.json (tests/ui-smoke.spec.ts, tests/ui-smoke.spec.ts, tests/ui-tools.spec.ts, tests/ui-tools.spec.ts) and re-run before bisecting.

Heuristic only — a main-side or flake label is a starting point, not a verdict.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/components/clinical-dashboard/use-universal-search.ts (1)

192-219: 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

"fresh" fallback ignores contextMode, allowing stale wrong-mode results to render as fresh.

fresh (Line 208) only compares result.query === trimmedQuery; it doesn't check result.contextMode === args.contextMode. When the active mode changes but the query stays the same, and the new (query, mode) combo isn't already cached, this hook returns the previous mode's groups, domainOrder, preferredDomains, topHit, and answerAction as loading: false until the debounced refetch resolves — i.e. every consumer (universal-search-command-surface.tsx, universal-search-also-matches.tsx in search-results-header-band.tsx/specifiers-home-page.tsx) can briefly render/rank results computed for the wrong mode. This undermines the mode-aware ordering that is the point of this PR, in a clinical decision-support surface.

The cached-snapshot path (Lines 194-207) is unaffected since cacheKey already encodes contextMode; only this fallback needs the fix.

🐛 Proposed fix
-  const fresh = result.query === trimmedQuery;
+  const fresh = result.query === trimmedQuery && result.contextMode === args.contextMode;
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/clinical-dashboard/use-universal-search.ts` around lines 192 -
219, Update the `fresh` check in the fallback result path to require both
`result.query === trimmedQuery` and `result.contextMode === args.contextMode`.
Keep the cached-snapshot branch unchanged, and continue returning empty or
undefined result fields with `loading: true` whenever either query or context
mode does not match.
🧹 Nitpick comments (2)
src/components/clinical-dashboard/universal-search-command-surface.tsx (2)

32-44: 📐 Maintainability & Code Quality | 🔵 Trivial

Stale comment references a removed mapping.

This comment still says "Reverse of modeIdByDomain", but per this same change that mapping was removed and replaced by universalSearchModeForDomain (imported at line 30). The comment is now misleading to future readers of domainsByTargetMode.

✏️ Suggested comment fix
-// Reverse of modeIdByDomain for chip counts: the domains whose live result totals a
-// cross-mode chip should sum. Answer/favourites chips have no countable domain; the
+// Domains whose live result totals a cross-mode chip should sum. Answer/favourites
+// chips have no countable domain; the
 // differentials chip counts both of its domains because the mode home search composes
 // presentations and diagnoses into one result list.
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/clinical-dashboard/universal-search-command-surface.tsx`
around lines 32 - 44, Update the comment above domainsByTargetMode to reference
universalSearchModeForDomain instead of the removed modeIdByDomain mapping,
while preserving the existing explanation of cross-mode chip domain aggregation.

57-106: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

standalone is a fragile proxy derived from primaryAction === "Run".

rankLocalFavourites gates cross-mode visibility (visibleFavouriteMatches at line 481-482) on this heuristic: only saved searches (primaryAction === "Run") and favourite sets are ever shown outside Favourites mode; individual saved items (medications/documents/sources with primaryAction like "Open"/"Ask"/"Source"/"Copy") never surface as "Also in Favourites". This may be intentional (avoiding duplicate entity display since those already surface via their native domain), but it's undocumented and relies on exact string equality against an unrelated FavouriteItem.primaryAction field rather than an explicit flag — a future favourite with a new primaryAction value would silently be excluded from cross-mode display with no compile-time signal.

Consider adding a short comment explaining the intent, or promoting this to an explicit field on FavouriteItem (e.g. crossModeVisible) so the contract is discoverable at the type level.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/components/clinical-dashboard/universal-search-command-surface.tsx`
around lines 57 - 106, Document the cross-mode visibility contract in
rankLocalFavourites: standalone should identify saved searches and favourite
sets, while individual saved entities remain excluded because they already
appear through native domain results. Prefer adding an explicit FavouriteItem
field such as crossModeVisible and use it instead of comparing primaryAction to
"Run"; otherwise add a concise comment explaining the intentional proxy.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/components/ClinicalDashboard.tsx`:
- Around line 3581-3591: Update the render guard around
UniversalSearchAlsoMatches so Answer mode remains eligible when
latestAnswerQuery is populated, even after query is cleared. Use the same
effective query selection as the component prop—latestAnswerQuery ?? query—for
the non-empty check, while preserving the existing result-kind restrictions and
behavior for Tools and Favourites.

---

Outside diff comments:
In `@src/components/clinical-dashboard/use-universal-search.ts`:
- Around line 192-219: Update the `fresh` check in the fallback result path to
require both `result.query === trimmedQuery` and `result.contextMode ===
args.contextMode`. Keep the cached-snapshot branch unchanged, and continue
returning empty or undefined result fields with `loading: true` whenever either
query or context mode does not match.

---

Nitpick comments:
In `@src/components/clinical-dashboard/universal-search-command-surface.tsx`:
- Around line 32-44: Update the comment above domainsByTargetMode to reference
universalSearchModeForDomain instead of the removed modeIdByDomain mapping,
while preserving the existing explanation of cross-mode chip domain aggregation.
- Around line 57-106: Document the cross-mode visibility contract in
rankLocalFavourites: standalone should identify saved searches and favourite
sets, while individual saved entities remain excluded because they already
appear through native domain results. Prefer adding an explicit FavouriteItem
field such as crossModeVisible and use it instead of comparing primaryAction to
"Run"; otherwise add a concise comment explaining the intentional proxy.
🪄 Autofix (Beta)

❌ Autofix failed (check again to retry)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 579ca0f7-b7ae-44d3-8b67-41a4a4da5bf4

📥 Commits

Reviewing files that changed from the base of the PR and between 1dcc4d9 and 01f587d.

📒 Files selected for processing (18)
  • src/app/api/search/universal/route.ts
  • src/components/ClinicalDashboard.tsx
  • src/components/clinical-dashboard/search-results-header-band.tsx
  • src/components/clinical-dashboard/universal-search-also-matches.tsx
  • src/components/clinical-dashboard/universal-search-command-surface.tsx
  • src/components/clinical-dashboard/use-universal-search.ts
  • src/components/services/services-navigator-page.tsx
  • src/components/specifiers/specifiers-home-page.tsx
  • src/lib/app-modes.ts
  • src/lib/search-command-surface.ts
  • src/lib/universal-search-domains.ts
  • src/lib/universal-search-mode-context.ts
  • src/lib/universal-search.ts
  • tests/app-modes.test.ts
  • tests/search-command-surface.test.ts
  • tests/ui-tools.spec.ts
  • tests/ui-universal-search.spec.ts
  • tests/universal-search.test.ts

Comment thread src/components/ClinicalDashboard.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: e53686c6bd

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/search-results-header-band.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4395a97809

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/search-results-header-band.tsx Outdated

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 7fe8ab6951

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/universal-search-command-surface.tsx Outdated
@BigSimmo

Copy link
Copy Markdown
Owner Author

@copilot resolve the merge conflicts on this branch.

auto-merge was automatically disabled July 14, 2026 13:43

Head branch was pushed to by a user without write access

…h-mode-ranking

# Conflicts:
#	src/components/formulation/formulation-home-page.tsx
#	src/lib/app-modes.ts
BigSimmo and others added 3 commits July 14, 2026 21:56
…ing' into codex/universal-search-mode-ranking

# Conflicts:
#	src/components/formulation/formulation-home-page.tsx
#	src/lib/app-modes.ts
@BigSimmo
BigSimmo enabled auto-merge (squash) July 14, 2026 13:59
…ing' into codex/universal-search-mode-ranking

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 972d45ea5b

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/components/clinical-dashboard/universal-search-also-matches.tsx
@BigSimmo
BigSimmo disabled auto-merge July 14, 2026 14:17
@coderabbitai

coderabbitai Bot commented Jul 14, 2026

Copy link
Copy Markdown
Contributor

Note

Autofix is a beta feature. Expect some limitations and changes as we gather feedback and continue to improve it.

Autofix skipped. No unresolved CodeRabbit review comments with fix instructions found.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants